/*     */ package com.zimbra.cs.mailbox;
/*     */ 
/*     */ import com.google.common.base.Strings;
/*     */ import com.google.common.collect.TreeMultimap;
/*     */ import com.zimbra.common.account.Key.AccountBy;
/*     */ import com.zimbra.common.mailbox.ContactConstants;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.soap.MailConstants;
/*     */ import com.zimbra.common.soap.SoapHttpTransport;
/*     */ import com.zimbra.common.soap.SoapProtocol;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.GalContact;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.gal.GalSearchControl;
/*     */ import com.zimbra.cs.gal.GalSearchParams;
/*     */ import com.zimbra.cs.gal.GalSearchResultCallback;
/*     */ import com.zimbra.cs.httpclient.URLUtil;
/*     */ import com.zimbra.cs.mime.ParsedContact;
/*     */ import com.zimbra.cs.service.util.ItemId;
/*     */ import com.zimbra.soap.type.GalSearchType;
/*     */ import java.io.IOException;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Arrays;
/*     */ import java.util.Collection;
/*     */ import java.util.Collections;
/*     */ import java.util.HashSet;
/*     */ import java.util.LinkedHashSet;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ import java.util.regex.Matcher;
/*     */ import java.util.regex.Pattern;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class ContactGroup
/*     */ {
/*     */   private Set<Member> members;
/*     */   private TreeMultimap<String, Member> derefedMembers;
/*     */   
/*     */   private static enum MetadataKey
/*     */   {
/*  59 */     MEMBERS("m");
/*     */     
/*     */     private String key;
/*     */     
/*  63 */     private MetadataKey(String key) { this.key = key; }
/*     */     
/*     */     private String getKey()
/*     */     {
/*  67 */       return this.key;
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public ContactGroup()
/*     */   {
/*  78 */     this.members = new LinkedHashSet();
/*     */     
/*     */ 
/*     */ 
/*  82 */     this.derefedMembers = null;
/*     */   }
/*     */   
/*     */   public static ContactGroup init(Contact contact, boolean createIfNotExist) throws ServiceException {
/*  86 */     ContactGroup contactGroup = null;
/*  87 */     if (contact != null) {
/*  88 */       String encoded = contact.get(ContactConstants.A_groupMember);
/*  89 */       if (encoded != null) {
/*  90 */         contactGroup = init(encoded);
/*     */       }
/*     */     }
/*     */     
/*  94 */     if ((contactGroup == null) && (createIfNotExist)) {
/*  95 */       contactGroup = init();
/*     */     }
/*  97 */     return contactGroup;
/*     */   }
/*     */   
/*     */   public static ContactGroup init(String encoded) throws ServiceException {
/* 101 */     return decode(encoded);
/*     */   }
/*     */   
/*     */   public static ContactGroup init() throws ServiceException {
/* 105 */     return new ContactGroup();
/*     */   }
/*     */   
/*     */   private boolean isDerefed() {
/* 109 */     return this.derefedMembers != null;
/*     */   }
/*     */   
/*     */   public boolean hasMembers() {
/* 113 */     return this.members.size() > 0;
/*     */   }
/*     */   
/*     */   public void removeAllMembers() {
/* 117 */     this.members.clear();
/* 118 */     this.derefedMembers = null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public List<Member> getMembers()
/*     */   {
/* 125 */     return Collections.unmodifiableList(Arrays.asList(this.members.toArray(new Member[this.members.size()])));
/*     */   }
/*     */   
/*     */   public List<Member> getMembers(boolean preferDerefed) {
/* 129 */     if ((preferDerefed) && (isDerefed())) {
/* 130 */       return getDerefedMembers();
/*     */     }
/* 132 */     return getMembers();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   public List<Member> getDerefedMembers()
/*     */   {
/* 140 */     assert (isDerefed());
/* 141 */     return Collections.unmodifiableList(Arrays.asList(this.derefedMembers.values().toArray(new Member[this.derefedMembers.size()])));
/*     */   }
/*     */   
/*     */   public Member addMember(ContactGroup.Member.Type type, String value) throws ServiceException
/*     */   {
/* 146 */     Member member = Member.init(type, value);
/* 147 */     if (this.members.contains(member)) {
/* 148 */       throw ServiceException.INVALID_REQUEST("member already exists: (" + type.soapEncoded + ")" + " " + value, null);
/*     */     }
/*     */     
/* 151 */     addMember(member);
/* 152 */     return member;
/*     */   }
/*     */   
/*     */   public void removeMember(ContactGroup.Member.Type type, String value) throws ServiceException {
/* 156 */     Member member = Member.init(type, value);
/* 157 */     if (!this.members.contains(member)) {
/* 158 */       throw ServiceException.INVALID_REQUEST("no such member: (" + type.soapEncoded + ")" + " " + value, null);
/*     */     }
/*     */     
/* 161 */     this.members.remove(member);
/*     */   }
/*     */   
/*     */ 
/*     */   public void migrateFromDlist(String dlist)
/*     */     throws ServiceException
/*     */   {
/* 168 */     String before = dump();
/* 169 */     removeAllMembers();
/* 170 */     MigrateContactGroup.migrate(this, dlist);
/*     */     
/* 172 */     ZimbraLog.contact.info("in-place migrated contact group from dlist: dlist=[%s], groupMember before migrate=[%s], groupMember after migrate=[%s]", new Object[] { dlist, before, dump() });
/*     */   }
/*     */   
/*     */ 
/*     */   public String migrateToDlist(Mailbox mbox, OperationContext octxt)
/*     */     throws ServiceException
/*     */   {
/* 179 */     List<String> addrs = getEmailAddresses(false, mbox, octxt, false);
/* 180 */     if (addrs.isEmpty()) {
/* 181 */       return null;
/*     */     }
/* 183 */     StringBuilder sb = new StringBuilder();
/* 184 */     boolean first = true;
/* 185 */     for (String addr : addrs) {
/* 186 */       if (first) {
/* 187 */         first = false;
/*     */       } else {
/* 189 */         sb.append(", ");
/*     */       }
/* 191 */       sb.append(addr);
/*     */     }
/*     */     
/* 194 */     if (ZimbraLog.contact.isDebugEnabled()) {
/* 195 */       ZimbraLog.contact.debug("returned contact group as dlist: dlist=[%s], groupMember=[%s]", new Object[] { sb.toString(), dump() });
/*     */     }
/*     */     
/*     */ 
/* 199 */     return sb.toString();
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   private void addMember(Member member)
/*     */   {
/* 206 */     this.members.add(member);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void derefAllMembers(Mailbox mbox, OperationContext octxt)
/*     */   {
/* 220 */     derefAllMembers(mbox, octxt, SoapProtocol.Soap12);
/*     */   }
/*     */   
/*     */   public void derefAllMembers(Mailbox mbox, OperationContext octxt, SoapProtocol proxyProtocol) {
/* 224 */     this.derefedMembers = TreeMultimap.create();
/*     */     
/* 226 */     for (Member member : this.members) {
/* 227 */       member.derefMember(mbox, octxt, proxyProtocol);
/* 228 */       if (member.derefed()) {
/* 229 */         String key = member.getDerefedKey();
/* 230 */         this.derefedMembers.put(key, member);
/*     */       } else {
/* 232 */         ZimbraLog.contact.debug("contact group member cannot be derefed: " + member.getValue());
/* 233 */         this.derefedMembers.put(member.getValue(), member);
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public List<String> getInlineEmailAddresses() {
/* 239 */     return getEmailAddresses(false, null, null, true);
/*     */   }
/*     */   
/*     */   public List<String> getEmailAddresses(boolean refresh, Mailbox mbox, OperationContext octxt, boolean inlineMembersOnly)
/*     */   {
/* 244 */     List<String> result = new ArrayList();
/*     */     
/* 246 */     if (inlineMembersOnly) {
/* 247 */       for (Member member : this.members) {
/* 248 */         if (ContactGroup.Member.Type.INLINE == member.getType()) {
/* 249 */           result.add(member.getValue());
/*     */         }
/*     */       }
/*     */     } else {
/* 253 */       if ((refresh) || (!isDerefed())) {
/* 254 */         derefAllMembers(mbox, octxt);
/*     */       }
/*     */       
/* 257 */       for (Member member : this.members) {
/* 258 */         member.getDerefedEmailAddresses(result);
/*     */       }
/*     */     }
/* 261 */     return result;
/*     */   }
/*     */   
/*     */   public String encode() {
/* 265 */     Metadata encoded = new Metadata();
/*     */     
/* 267 */     MetadataList encodedMembers = new MetadataList();
/* 268 */     for (Member member : this.members) {
/* 269 */       encodedMembers.add(member.encode());
/*     */     }
/*     */     
/* 272 */     encoded.put(MetadataKey.MEMBERS.getKey(), encodedMembers);
/*     */     
/* 274 */     return encoded.toString();
/*     */   }
/*     */   
/*     */   private static ContactGroup decode(String encodedStr) throws ServiceException {
/*     */     try {
/* 279 */       Metadata encoded = new Metadata(encodedStr);
/*     */       
/* 281 */       ContactGroup contactGroup = new ContactGroup();
/*     */       
/* 283 */       MetadataList members = encoded.getList(MetadataKey.MEMBERS.getKey());
/* 284 */       if (members == null) {
/* 285 */         throw ServiceException.FAILURE("missing members in metadata", null);
/*     */       }
/*     */       
/* 288 */       List<Metadata> memberList = members.asList();
/* 289 */       for (Metadata encodedMember : memberList) {
/* 290 */         Member member = Member.decode(encodedMember);
/* 291 */         contactGroup.addMember(member);
/*     */       }
/* 293 */       return contactGroup;
/*     */     }
/*     */     catch (ServiceException e) {
/* 296 */       ZimbraLog.contact.warn("unabale to decode contact group", e);
/* 297 */       throw e;
/*     */     }
/*     */   }
/*     */   
/*     */   private String dump()
/*     */   {
/* 303 */     StringBuilder sb = new StringBuilder();
/* 304 */     boolean first = true;
/* 305 */     for (Member member : this.members) {
/* 306 */       if (!first) {
/* 307 */         sb.append(", ");
/*     */       } else {
/* 309 */         first = false;
/*     */       }
/* 311 */       sb.append(member.getType().getMetaDataEncoded() + ":" + member.getValue());
/*     */     }
/* 313 */     return sb.toString();
/*     */   }
/*     */   
/*     */   public static abstract class Member implements Comparable<Member>
/*     */   {
/*     */     protected String value;
/*     */     private String derefedKey;
/*     */     private List<String> derefedEmailAddrs;
/*     */     private Object derefedObject;
/*     */     
/*     */     private static enum MetadataKey
/*     */     {
/* 325 */       ID("id"), 
/* 326 */       TYPE("t"), 
/* 327 */       VALUE("v");
/*     */       
/*     */       private String key;
/*     */       
/* 331 */       private MetadataKey(String key) { this.key = key; }
/*     */       
/*     */       private String getKey()
/*     */       {
/* 335 */         return this.key;
/*     */       }
/*     */     }
/*     */     
/*     */     public static enum Type
/*     */     {
/* 341 */       CONTACT_REF("C", "C", "memberC"), 
/* 342 */       GAL_REF("G", "G", "memberG"), 
/* 343 */       INLINE("I", "I", "memberI");
/*     */       
/*     */       private String metadataEncoded;
/*     */       private String soapEncoded;
/*     */       private String delimittedFieldsEncoded;
/*     */       
/*     */       private Type(String metadataEncoded, String soapEncoded, String delimittedFieldsEncoded) {
/* 350 */         this.metadataEncoded = metadataEncoded;
/* 351 */         this.soapEncoded = soapEncoded;
/* 352 */         this.delimittedFieldsEncoded = delimittedFieldsEncoded;
/*     */       }
/*     */       
/*     */       private String getMetaDataEncoded() {
/* 356 */         return this.metadataEncoded;
/*     */       }
/*     */       
/*     */       public String getSoapEncoded() {
/* 360 */         return this.soapEncoded;
/*     */       }
/*     */       
/*     */       public String getDelimittedFieldsEncoded() {
/* 364 */         return this.delimittedFieldsEncoded;
/*     */       }
/*     */       
/*     */       private static Type fromMetadata(String metadataEncoded) throws ServiceException {
/* 368 */         if (CONTACT_REF.getMetaDataEncoded().equals(metadataEncoded))
/* 369 */           return CONTACT_REF;
/* 370 */         if (GAL_REF.getMetaDataEncoded().equals(metadataEncoded))
/* 371 */           return GAL_REF;
/* 372 */         if (INLINE.getMetaDataEncoded().equals(metadataEncoded)) {
/* 373 */           return INLINE;
/*     */         }
/*     */         
/* 376 */         throw ServiceException.FAILURE("Unrecognized member type: " + metadataEncoded, null);
/*     */       }
/*     */       
/*     */       public static Type fromSoap(String soapEncoded) throws ServiceException {
/* 380 */         if (soapEncoded == null)
/* 381 */           return null;
/* 382 */         if (CONTACT_REF.getSoapEncoded().equals(soapEncoded))
/* 383 */           return CONTACT_REF;
/* 384 */         if (GAL_REF.getSoapEncoded().equals(soapEncoded))
/* 385 */           return GAL_REF;
/* 386 */         if (INLINE.getSoapEncoded().equals(soapEncoded)) {
/* 387 */           return INLINE;
/*     */         }
/*     */         
/* 390 */         throw ServiceException.INVALID_REQUEST("Unrecognized member type: " + soapEncoded, null);
/*     */       }
/*     */     }
/*     */     
/*     */     private static Member init(Type type, String value) throws ServiceException {
/* 395 */       Member member = null;
/* 396 */       switch (ContactGroup.1.$SwitchMap$com$zimbra$cs$mailbox$ContactGroup$Member$Type[type.ordinal()]) {
/*     */       case 1: 
/* 398 */         member = new ContactGroup.ContactRefMember(value);
/* 399 */         break;
/*     */       case 2: 
/* 401 */         member = new ContactGroup.GalRefMember(value);
/* 402 */         break;
/*     */       case 3: 
/* 404 */         member = new ContactGroup.InlineMember(value);
/* 405 */         break;
/*     */       default: 
/* 407 */         throw ServiceException.INVALID_REQUEST("Unrecognized member type: " + type.name(), null);
/*     */       }
/* 409 */       return member;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */     public abstract Type getType();
/*     */     
/*     */ 
/*     */ 
/*     */     protected abstract void deref(Mailbox paramMailbox, OperationContext paramOperationContext, SoapProtocol paramSoapProtocol)
/*     */       throws ServiceException;
/*     */     
/*     */ 
/*     */     protected Member(String value)
/*     */       throws ServiceException
/*     */     {
/* 425 */       setValue(value);
/*     */     }
/*     */     
/*     */     private String getKey() {
/* 429 */       return getType().getMetaDataEncoded() + this.value;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */     public int hashCode()
/*     */     {
/* 437 */       return getKey().hashCode();
/*     */     }
/*     */     
/*     */     public boolean equals(Object other)
/*     */     {
/* 442 */       if ((other instanceof Member)) {
/* 443 */         return hashCode() == other.hashCode();
/*     */       }
/* 445 */       return false;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */     public int compareTo(Member other)
/*     */     {
/* 459 */       return getKey().compareTo(other.getKey());
/*     */     }
/*     */     
/*     */     public String getValue() {
/* 463 */       return this.value;
/*     */     }
/*     */     
/*     */     public String getDerefedKey() {
/* 467 */       assert (derefed());
/* 468 */       return this.derefedKey;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */     private List<String> getDerefedEmailAddresses(List<String> result)
/*     */     {
/* 475 */       assert (derefed());
/* 476 */       if (result == null) {
/* 477 */         result = new ArrayList();
/*     */       }
/*     */       
/* 480 */       if (this.derefedEmailAddrs != null) {
/* 481 */         result.addAll(this.derefedEmailAddrs);
/*     */       }
/* 483 */       return result;
/*     */     }
/*     */     
/*     */     public Object getDerefedObj() {
/* 487 */       return this.derefedObject;
/*     */     }
/*     */     
/*     */     protected boolean derefed() {
/* 491 */       return this.derefedObject != null;
/*     */     }
/*     */     
/*     */     private void derefMember(Mailbox mbox, OperationContext octxt, SoapProtocol proxyProtocol) {
/* 495 */       if (!derefed()) {
/*     */         try {
/* 497 */           deref(mbox, octxt, proxyProtocol);
/*     */         }
/*     */         catch (ServiceException e) {
/* 500 */           ZimbraLog.contact.warn("unable to deref contact group member: " + this.value, e);
/*     */         }
/*     */       }
/*     */     }
/*     */     
/*     */     private void setValue(String value) throws ServiceException {
/* 506 */       if (StringUtil.isNullOrEmpty(value)) {
/* 507 */         throw ServiceException.INVALID_REQUEST("missing value", null);
/*     */       }
/* 509 */       this.value = value;
/*     */     }
/*     */     
/*     */     private void setDerefedKey(String key) {
/* 513 */       if (key == null) {
/* 514 */         key = "";
/*     */       }
/* 516 */       this.derefedKey = key;
/*     */     }
/*     */     
/*     */     private void setDerefedEmailAddrs(List<String> emaiLAddrs) {
/* 520 */       this.derefedEmailAddrs = emaiLAddrs;
/*     */     }
/*     */     
/*     */     protected void setDerefedObject(Object obj, String key, List<String> emailAddrs) {
/* 524 */       if (obj != null) {
/* 525 */         setDerefedKey(key);
/* 526 */         setDerefedEmailAddrs(emailAddrs);
/*     */       }
/* 528 */       this.derefedObject = obj;
/*     */     }
/*     */     
/*     */     private Metadata encode() {
/* 532 */       Metadata encoded = new Metadata();
/* 533 */       encoded.put(MetadataKey.TYPE.getKey(), getType().getMetaDataEncoded());
/* 534 */       encoded.put(MetadataKey.VALUE.getKey(), this.value);
/* 535 */       return encoded;
/*     */     }
/*     */     
/*     */     private static Member decode(Metadata encoded) throws ServiceException {
/* 539 */       String encodedType = encoded.get(MetadataKey.TYPE.getKey());
/* 540 */       String value = encoded.get(MetadataKey.VALUE.getKey());
/*     */       
/* 542 */       Type type = Type.fromMetadata(encodedType);
/* 543 */       return init(type, value);
/*     */     }
/*     */   }
/*     */   
/*     */   public static class ContactRefMember extends ContactGroup.Member {
/*     */     public ContactRefMember(String value) throws ServiceException {
/* 549 */       super();
/*     */     }
/*     */     
/*     */     public ContactGroup.Member.Type getType()
/*     */     {
/* 554 */       return ContactGroup.Member.Type.CONTACT_REF;
/*     */     }
/*     */     
/*     */     private String genDerefedKey(Contact contact) throws ServiceException {
/* 558 */       return contact.getFileAsString();
/*     */     }
/*     */     
/*     */     private String genDerefedKey(Element eContact) throws ServiceException {
/* 562 */       return eContact.getAttribute("fileAsStr", null);
/*     */     }
/*     */     
/*     */     private List<String> genDerefedEmailAddrs(Account ownerAcct, Contact contact) {
/* 566 */       String[] emailFields = Contact.getEmailFields(ownerAcct);
/* 567 */       Map<String, String> fieldMap = contact.getAllFields();
/*     */       
/* 569 */       List<String> result = new ArrayList();
/* 570 */       for (String field : emailFields) {
/* 571 */         String addr = (String)fieldMap.get(field);
/* 572 */         if ((addr != null) && (!addr.trim().isEmpty())) {
/* 573 */           result.add(addr);
/*     */         }
/*     */       }
/* 576 */       return result;
/*     */     }
/*     */     
/*     */     private List<String> genDerefedEmailAddrs(Account ownerAcct, Element eContact) {
/* 580 */       String[] emailFields = Contact.getEmailFields(ownerAcct);
/* 581 */       Set<String> emailFieldsSet = new HashSet(Arrays.asList(emailFields));
/*     */       
/* 583 */       List<String> result = new ArrayList();
/* 584 */       for (Element eAttr : eContact.listElements("a")) {
/* 585 */         String field = eAttr.getAttribute("n", null);
/* 586 */         if ((field != null) && (emailFieldsSet.contains(field))) {
/* 587 */           String content = eAttr.getText();
/* 588 */           if (!Strings.isNullOrEmpty(content)) {
/* 589 */             result.add(content);
/*     */           }
/*     */         }
/*     */       }
/*     */       
/* 594 */       return result;
/*     */     }
/*     */     
/*     */     protected void deref(Mailbox requestedMbox, OperationContext octxt, SoapProtocol proxyProtocol)
/*     */       throws ServiceException
/*     */     {
/* 600 */       Object obj = null;
/* 601 */       String key = null;
/* 602 */       List<String> emailAddrs = null;
/*     */       
/* 604 */       ItemId itemId = new ItemId(this.value, requestedMbox.getAccountId());
/* 605 */       String ownerAcctId = itemId.getAccountId();
/* 606 */       Account ownerAcct = Provisioning.getInstance().get(Key.AccountBy.id, ownerAcctId);
/* 607 */       if (ownerAcct == null) {
/* 608 */         ZimbraLog.contact.debug("no such account for contact group member: " + itemId.toString());
/* 609 */         return;
/*     */       }
/*     */       
/* 612 */       if (itemId.isLocal()) {
/* 613 */         Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(itemId.getAccountId(), false);
/* 614 */         Contact contact = mbox.getContactById(octxt, itemId.getId());
/* 615 */         if (contact != null) {
/* 616 */           obj = contact;
/* 617 */           key = genDerefedKey(contact);
/* 618 */           emailAddrs = genDerefedEmailAddrs(ownerAcct, contact);
/*     */         }
/*     */       } else {
/* 621 */         AuthToken authToken = AuthToken.getCsrfUnsecuredAuthToken(octxt.getAuthToken());
/* 622 */         Element eContact = fetchRemoteContact(authToken, ownerAcct, itemId, proxyProtocol);
/* 623 */         if (eContact != null) {
/* 624 */           obj = eContact;
/* 625 */           key = genDerefedKey(eContact);
/* 626 */           emailAddrs = genDerefedEmailAddrs(ownerAcct, eContact);
/*     */         }
/*     */       }
/*     */       
/* 630 */       setDerefedObject(obj, key, emailAddrs);
/*     */     }
/*     */     
/*     */     private Element fetchRemoteContact(AuthToken authToken, Account ownerAcct, ItemId contactId, SoapProtocol proxyProtocol)
/*     */       throws ServiceException
/*     */     {
/* 636 */       Provisioning prov = Provisioning.getInstance();
/*     */       
/* 638 */       String serverUrl = URLUtil.getAdminURL(prov.getServerByName(ownerAcct.getMailHost()));
/* 639 */       SoapHttpTransport transport = new SoapHttpTransport(serverUrl);
/* 640 */       transport.setAuthToken(authToken.toZAuthToken());
/* 641 */       transport.setTargetAcctId(ownerAcct.getId());
/*     */       
/* 643 */       Element request = Element.create(proxyProtocol, MailConstants.GET_CONTACTS_REQUEST);
/* 644 */       Element eContact = request.addElement("cn");
/* 645 */       eContact.addAttribute("id", contactId.toString());
/*     */       Element response;
/*     */       try
/*     */       {
/* 649 */         response = transport.invokeWithoutSession(request);
/*     */       } catch (IOException e) {
/* 651 */         ZimbraLog.contact.debug("unable to fetch remote member ", e);
/* 652 */         throw ServiceException.PROXY_ERROR("unable to fetch remote member " + contactId.toString(), serverUrl);
/*     */       }
/* 654 */       Element eGotContact = response.getOptionalElement("cn");
/* 655 */       if (eGotContact != null) {
/* 656 */         eGotContact.detach();
/*     */       }
/* 658 */       return eGotContact;
/*     */     }
/*     */   }
/*     */   
/*     */   public static class GalRefMember extends ContactGroup.Member {
/*     */     private static final String PRIMARY_EMAIL_FIELD = "email";
/* 664 */     private static final Set<String> GAL_EMAIL_FIELDS = new HashSet(Arrays.asList(new String[] { "email", "email2", "email3", "email4", "email5", "email6", "email7", "email8", "email9", "email10", "email11", "email12", "email13", "email14", "email15", "email16" }));
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */     public GalRefMember(String value)
/*     */       throws ServiceException
/*     */     {
/* 672 */       super();
/*     */     }
/*     */     
/*     */     public ContactGroup.Member.Type getType()
/*     */     {
/* 677 */       return ContactGroup.Member.Type.GAL_REF;
/*     */     }
/*     */     
/*     */     private String genDerefedKey(Contact contact) throws ServiceException {
/* 681 */       String key = contact.get(ContactConstants.A_email);
/* 682 */       if (key == null) {
/* 683 */         key = contact.getFileAsString();
/*     */       }
/* 685 */       return key;
/*     */     }
/*     */     
/*     */     private String genDerefedKey(GalContact galContact) throws ServiceException {
/* 689 */       String key = galContact.getSingleAttr(ContactConstants.A_email);
/* 690 */       if (key == null) {
/* 691 */         key = galContact.getSingleAttr(ContactConstants.A_fullName);
/*     */       }
/* 693 */       if (key == null) {
/* 694 */         key = galContact.getSingleAttr(ContactConstants.A_firstName) + " " + galContact.getSingleAttr(ContactConstants.A_lastName);
/*     */       }
/*     */       
/* 697 */       return key;
/*     */     }
/*     */     
/*     */     private String genDerefedKey(Element eContact) throws ServiceException
/*     */     {
/* 702 */       return eContact.getAttribute("fileAsStr", null);
/*     */     }
/*     */     
/*     */     private List<String> genDerefedEmailAddrs(Contact contact) {
/* 706 */       Map<String, String> fieldMap = contact.getAllFields();
/*     */       
/* 708 */       List<String> result = new ArrayList();
/* 709 */       for (String field : GAL_EMAIL_FIELDS) {
/* 710 */         String addr = (String)fieldMap.get(field);
/* 711 */         if ((addr != null) && (!addr.trim().isEmpty())) {
/* 712 */           result.add(addr);
/*     */         }
/*     */       }
/* 715 */       return result;
/*     */     }
/*     */     
/*     */     private List<String> genDerefedEmailAddrs(GalContact galContact) {
/* 719 */       Map<String, Object> fieldMap = galContact.getAttrs();
/*     */       
/* 721 */       List<String> result = new ArrayList();
/* 722 */       for (String field : GAL_EMAIL_FIELDS) {
/* 723 */         Object value = fieldMap.get(field);
/* 724 */         if ((value instanceof String)) {
/* 725 */           result.add((String)value);
/* 726 */         } else if ((value instanceof String[])) {
/* 727 */           String[] addrs = (String[])value;
/* 728 */           for (String addr : addrs) {
/* 729 */             result.add(addr);
/*     */           }
/*     */         }
/*     */       }
/* 733 */       return result;
/*     */     }
/*     */     
/*     */     private List<String> genDerefedEmailAddrs(Element eContact)
/*     */     {
/* 738 */       List<String> result = new ArrayList();
/* 739 */       for (Element eAttr : eContact.listElements("a")) {
/* 740 */         String field = eAttr.getAttribute("n", null);
/* 741 */         if ((field != null) && (GAL_EMAIL_FIELDS.contains(field))) {
/* 742 */           String content = eAttr.getText();
/* 743 */           if (!Strings.isNullOrEmpty(content)) {
/* 744 */             result.add(content);
/*     */           }
/*     */         }
/*     */       }
/*     */       
/* 749 */       return result;
/*     */     }
/*     */     
/*     */ 
/*     */     protected void deref(Mailbox mbox, OperationContext octxt, SoapProtocol proxyProtocol)
/*     */       throws ServiceException
/*     */     {
/* 756 */       GalSearchParams params = new GalSearchParams(mbox.getAccount(), null);
/* 757 */       params.setSearchEntryByDn(this.value);
/* 758 */       params.setType(GalSearchType.all);
/* 759 */       params.setLimit(1);
/* 760 */       params.setProxyProtocol(proxyProtocol);
/*     */       
/*     */ 
/* 763 */       ContactGroupResultCallback callback = new ContactGroupResultCallback(params);
/* 764 */       params.setResultCallback(callback);
/*     */       
/* 766 */       GalSearchControl gal = new GalSearchControl(params);
/* 767 */       gal.search();
/*     */       
/* 769 */       Object obj = callback.getResult();
/* 770 */       String key = null;
/* 771 */       List<String> emailAddrs = null;
/*     */       
/* 773 */       if (obj != null) {
/* 774 */         if ((obj instanceof Contact)) {
/* 775 */           Contact contact = (Contact)obj;
/* 776 */           key = genDerefedKey(contact);
/* 777 */           emailAddrs = genDerefedEmailAddrs(contact);
/* 778 */         } else if ((obj instanceof GalContact)) {
/* 779 */           GalContact galContact = (GalContact)obj;
/* 780 */           key = genDerefedKey(galContact);
/* 781 */           emailAddrs = genDerefedEmailAddrs(galContact);
/* 782 */         } else if ((obj instanceof Element)) {
/* 783 */           Element eContact = (Element)obj;
/* 784 */           key = genDerefedKey(eContact);
/* 785 */           emailAddrs = genDerefedEmailAddrs(eContact);
/*     */         }
/*     */       }
/*     */       
/* 789 */       setDerefedObject(obj, key, emailAddrs);
/*     */     }
/*     */     
/*     */     private static class ContactGroupResultCallback extends GalSearchResultCallback {
/*     */       Object result;
/*     */       
/*     */       public ContactGroupResultCallback(GalSearchParams params) {
/* 796 */         super();
/*     */       }
/*     */       
/*     */       private Object getResult() {
/* 800 */         return this.result;
/*     */       }
/*     */       
/*     */       public Element handleContact(Contact contact) throws ServiceException
/*     */       {
/* 805 */         this.result = contact;
/* 806 */         return null;
/*     */       }
/*     */       
/*     */       public void handleContact(GalContact galContact) throws ServiceException
/*     */       {
/* 811 */         this.result = galContact;
/*     */       }
/*     */       
/*     */       public void handleElement(Element element) throws ServiceException
/*     */       {
/* 816 */         element.detach();
/* 817 */         this.result = element;
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public static class InlineMember extends ContactGroup.Member
/*     */   {
/*     */     public InlineMember(String value) throws ServiceException {
/* 825 */       super();
/*     */     }
/*     */     
/*     */     public ContactGroup.Member.Type getType()
/*     */     {
/* 830 */       return ContactGroup.Member.Type.INLINE;
/*     */     }
/*     */     
/*     */ 
/*     */     protected void deref(Mailbox mbox, OperationContext octxt, SoapProtocol proxyProtocol)
/*     */     {
/* 836 */       List<String> emailAddrs = new ArrayList();
/* 837 */       emailAddrs.add(this.value);
/*     */       
/* 839 */       setDerefedObject(this.value, this.value, emailAddrs);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static class MigrateContactGroup
/*     */   {
/* 861 */     private static final Pattern PATTERN = Pattern.compile("(([\\s]*)(\"[^\"]*\")*[^,]*[,]*)");
/*     */     private Mailbox mbox;
/*     */     private OperationContext octxt;
/*     */     
/*     */     public MigrateContactGroup(Mailbox mbox) throws ServiceException
/*     */     {
/* 867 */       this.mbox = mbox;
/* 868 */       this.octxt = new OperationContext(mbox);
/*     */     }
/*     */     
/*     */     public void handle() throws ServiceException {
/* 872 */       for (MailItem item : this.mbox.getItemList(this.octxt, MailItem.Type.CONTACT, -1)) {
/* 873 */         Contact contact = (Contact)item;
/*     */         try {
/* 875 */           migrate(contact);
/*     */         } catch (Exception e) {
/* 877 */           if (contact.isGroup()) {
/* 878 */             ZimbraLog.contact.info("skipped migrating contact group %d", Integer.valueOf(contact.getId()), e);
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */     
/*     */     public void migrate(Contact contact) throws ServiceException {
/* 885 */       if (!contact.isGroup()) {
/* 886 */         return;
/*     */       }
/*     */       
/* 889 */       String dlist = contact.get(ContactConstants.A_dlist);
/* 890 */       if (Strings.isNullOrEmpty(dlist)) {
/* 891 */         ZimbraLog.contact.info("skipped migrating contact group %d as dlist is empty", new Object[] { Integer.valueOf(contact.getId()) });
/* 892 */         return;
/*     */       }
/*     */       
/* 895 */       ContactGroup contactGroup = ContactGroup.init();
/*     */       
/* 897 */       migrate(contactGroup, dlist);
/*     */       
/* 899 */       if (contactGroup.hasMembers()) {
/* 900 */         ParsedContact pc = new ParsedContact(contact);
/*     */         
/* 902 */         pc.modifyField(ContactConstants.A_groupMember, contactGroup.encode());
/*     */         
/*     */ 
/*     */ 
/*     */ 
/* 907 */         pc.modifyField(ContactConstants.A_dlist, null);
/*     */         
/* 909 */         this.mbox.modifyContact(this.octxt, contact.getId(), pc);
/*     */         
/* 911 */         ZimbraLog.contact.info("migrated contact group %s: dlist=[%s], groupMember=[%s]", new Object[] { Integer.valueOf(contact.getId()), dlist, contactGroup.dump() });
/*     */       }
/*     */       else {
/* 914 */         ZimbraLog.contact.info("aborted migrating contact group %d: dlist=[%s]", new Object[] { Integer.valueOf(contact.getId()), dlist });
/*     */       }
/*     */     }
/*     */     
/*     */     static void migrate(ContactGroup contactGroup, String dlist) throws ServiceException
/*     */     {
/* 920 */       Matcher matcher = PATTERN.matcher(dlist);
/* 921 */       while (matcher.find()) {
/* 922 */         String token = matcher.group();
/* 923 */         int len = token.length();
/* 924 */         if (len > 0) {
/* 925 */           if (token.charAt(len - 1) == ',') {
/* 926 */             token = token.substring(0, len - 1);
/*     */           }
/* 928 */           String addr = token.trim();
/* 929 */           if (!addr.isEmpty()) {
/*     */             try {
/* 931 */               contactGroup.addMember(ContactGroup.Member.Type.INLINE, addr);
/*     */             } catch (ServiceException e) {
/* 933 */               ZimbraLog.contact.info("skipped contact group member %s", new Object[] { addr });
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/ContactGroup.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */